<?php
/**
 * post相关函数 - JBlog
 * 
 * @copyright (c) 2008-2010 JBlog (www.lisijie.org)
 * @author lisijie <lisijie86@gmail.com>
 * @version $Id: func_post.php 523 2010-06-23 10:06:24Z lisijie86 $
*/

!defined('IN_JBLOG') && exit('Access Denied!');

/**
 * 文章发布
 * 
 * Jblog v2 中，所有内容数据均存储在post表中，方便扩展
 * 表单名称必须与post表的字段名相对应，如提交的数据中存在id字段，则视为修改
 * 附件字段使用名为 meta 的数组存放
 * 
 * @param array $post  过滤后的$_POST数据
 * @param array $old   旧记录内容，修改记录时需传递
 * @return int 返回记录ID
 */
function post_post($post, $old = array()) {
	global $db,$_USER;
	$post = apply_filter('post_post', $post);
	$update = array();
	$data = array(
		'cateid'      => intval($post['cateid']),
		'parentid'	  => intval($post['parentid']),
		'userid'      => $_USER['id'],
		'username'    => $_USER['name'],
		'title'       => check_str($post['title']),
		'alias'	      => preg_match('/^[a-z]+[a-z0-9\-_\.]+$/i',$post['alias']) ? $post['alias'] : '',
		'password'    => trim($post['password']),
		'excerpt'     => trim($post['excerpt']),
		'content'     => trim($post['content']),
		'dateline'    => $post['dateline'] ? intval($post['dateline']) : NOW,
		'type'        => trim($post['type']),
		'commentstatus'   => $post['commentstatus']?1:0,
		'status'      => 0,
	);
	//文章状态
	if ( is_admin() || !check_perm('blog','needcheck') ) {
		$data['status'] = 1;
	}
	//自动摘要
	if ( !$post['id'] && config('auto_excerpt') ) {
		if ( preg_match('|<p>(.*?)</p>|is', $data['content'], $matches) ) {
			$data['excerpt'] = trim(strip_tags($matches[1]));
		}
		if (empty($data['excerpt'])) {
			$data['excerpt'] = cut_str(trim(strip_tags($data['content'])), 255);
		}
		$data['excerpt'] = '<p>'.$data['excerpt'].'</p>';		
	}
	//插入到主表
	if ( $post['id'] ) {
		$postid = intval($post['id']);
		unset($data['userid'], $data['username']);
		$db->update('post', $data, array('id' => $postid));
	} else {
		$postid = $db->insert('post', $data);
		$db->query("UPDATE ".tname('cate')." SET `count` = `count` + 1 WHERE id = '$data[cateid]'");
		$db->query("UPDATE ".tname('user')." SET posts = posts + 1 WHERE id = '$_USER[id]'");
	}
	//自定义元数据
	if ( $post['metas'] ) {
		global $_CACHE;
		get_cache($post['type'].'meta');
		$postmeta = $_CACHE[$post['type'].'meta'];
		$update['metas'] = 0;
		foreach ( $post['metas'] as $meta_name => $meta_value ) {
			if ( isset($postmeta[$meta_name]) ) {
				$db->insert('postmeta', array('postid'=>$postid, 'var'=>$meta_name, 'value'=>$meta_value), true);
				$update['metas'] ++;
			}
		}
	}
	//检查别名是否重复，重复则在后面加上该记录id
	if ( !empty($data['alias']) ) {
		if ( $db->result("SELECT id FROM ".tname('post')." WHERE id != '$postid' AND `alias` = '$post[alias]'") ) {
			$update['alias'] = $data['alias'].'_'.$postid;
		}
	}
	//标签处理
	if ( !empty($post['tags']) || (empty($post['tags'])&&!empty($old['tags'])) ) {
		$tags = $newtags = array();
		$post['tags'] = str_replace('，',',', $post['tags']);
		foreach (explode(',', $post['tags']) as $val) {
			if ( strlen($val) > 2 && !empty($val) && !in_array($val, $tags) ) $tags[] = check_str($val);
		}
		//清除旧标签数据
		if ( $old['tags'] ) {
			$db->delete('tagpost', array('postid' => $postid));
			$db->query("UPDATE ".tname('tag')." SET `count` = `count` - 1 WHERE tagname IN (".simplode(explode(',', $old['tags'])).")");
		}
		$update['tags'] = implode(',', $tags);
		$query = $db->query("SELECT id,tagname FROM ".tname('tag')." WHERE tagname IN (".simplode($tags).")");
		while ( $row = $db->fetch_array($query) ) {
				$newtags[$row['id']] = $row['tagname'];
		}
		foreach ( $tags as $_tag ) {
			if ( !in_array($_tag, $newtags) ) {
				$_tagid = $db->insert('tag', array('tagname'=>$_tag));
				$newtags[$_tagid] = $_tag;
			}
		}
		$insql = $sp = '';
		foreach ( $newtags as $_tagid => $_tag ) {
			$insql .= $sp."('$_tagid', '$postid')";
			$sp = ',';
		}
		$db->query("INSERT INTO ".tname('tagpost')." VALUES $insql");
		$db->query("UPDATE ".tname('tag')." SET `count` = `count` + 1 WHERE tagname IN (".simplode($tags).")");
	}
	if ( $update ) { 
		$db->update('post', $update, array('id'=>$postid));
	}
	return $postid;
}

/**
 * 批量删除帖子及其关联数据
 * 
 * 删除post下的meta、tag、comment等数据
 *
 * @param array $post_ids
 * @return bool
 */
function del_post($post_ids) {
	global $db;
	foreach ( (array)$post_ids as $key => $val ) {
		if ( !is_numeric($val) || !$val ) {
			unset($post_ids[$key]);
		} 
	}
	if ( empty($post_ids) ) return FALSE;
	$cids = $uids = $tagids = array();
	$query = $db->query("SELECT cateid, userid FROM ".tname('post')." WHERE id IN (".simplode($post_ids).")");
	while ( $row = $db->fetch_array($query) ) {
		if ( !isset($cids[$row['cateid']]) ) $cids[$row['cateid']] = 0;
		if ( !isset($uids[$row['userid']]) ) $uids[$row['userid']] = 0; 
		$cids[$row['cateid']]++;
		$uids[$row['userid']]++;
	} 
	//查询标签ID
	$query = $db->query("SELECT tagid, COUNT(*) AS num FROM ".tname('tagpost')." WHERE postid IN (".simplode($post_ids).") GROUP BY tagid");
	while ( $row = $db->fetch_array($query) ) {
		$tagids[$row['tagid']] = $row['num'];
	}
	//删除文章
	$db->query("DELETE FROM ".tname('post')." WHERE id IN (".simplode($post_ids).")");
	$db->query("DELETE FROM ".tname('postmeta')." WHERE postid IN (".simplode($post_ids).")");
	$db->query("DELETE FROM ".tname('comment')." WHERE postid IN (".simplode($post_ids).")");
	//删除日历
	$db->query("DELETE FROM ".tname('calendar')." WHERE postid IN (".simplode($post_ids).")");
	//删除标签
	$db->query("DELETE FROM ".tname('tagpost')." WHERE postid IN (".simplode($post_ids).")");
	//更新分类统计
	foreach ($cids as $cid => $num) {
		$db->query("UPDATE ".tname('cate')." SET `count` = `count` - $num WHERE id = '$cid'");
	}
	//更新用户统计
	foreach ( $uids as $uid => $num ) {
		$db->query("UPDATE ".tname('user')." SET posts = posts - $num WHERE id = '$uid'");
	}
	//更新标签统计
	foreach ($tagids as $tagid => $num) {
		$db->query("UPDATE ".tname('tag')." SET `count` = `count` - $num WHERE id = '$tagid'");
	}
	return TRUE;
}

/**
 * 添加文章自定义域
 * 
 * @param int $postid 文章ID
 * @param string $key 名称
 * @param string $value 值
 */
function add_post_meta($postid, $key, $value) {
	global $db;
	if ( empty($key) || !preg_match("/^[\x{4e00}-\x{9fa5}A-Za-z0-9_]+$/u", $key) ) return false;
	$meta = array(
		'postid' => (int)$postid,
		'var' => trim($key),
		'value' => trim($value),
	);
	$metaid = $db->insert('postmeta', $meta);
	$db->query("UPDATE ".tname('post')." SET metas = metas + 1 WHERE id = '$postid'");
	return $metaid;
}

/**
 * 提取一篇文章
 * 
 * @param string $key   字段值
 * @param string $field 字段名，默认字段为：id
 * @return array 返回一条post记录数组，记录不存在返回false
 */
function get_post($value, $field = 'id') {
	global $db;
	$sql = "SELECT * FROM ".tname('post')." WHERE `{$field}` = '$value' LIMIT 1";
	if ( $post = $db->fetch_one_array($sql) ) {
		if ( $post['metas'] ) {
			$sql = "SELECT id, `var`, `value` FROM ".tname('postmeta')." WHERE postid = '".$post['id']."'";
			$query = $db->query($sql);
			while ( $row = $db->fetch_array($query) ) {
				$post[$row['var']] = $row;
			}
		}
	}
	return $post;
}

/**
 * 文章查询接口
 * 
 * 从post表查询符合条件的记录，将每条记录内容缓存到$_CACHE['post']下，方便其他接口调用
 * 并将 键名 添加到 $_CACHE['list_类型']，用于循环
 * 
 * @param integer $offset   记录偏移量
 * @param integer $num    查询条数
 * @param string  $type     Post类型
 * @param string  $wheresql where条件语句
 * @param string  $field 查询字段，默认为所有
*/
function query_post($type = '', $offset = 0, $num = 0, $where='', $field = '*') {
	global $_CACHE,$db;
	$wheresql = '';
	if ( $where ) {
		$wheresql .= " AND $where";
	}
	if ( $type ) {
		$wheresql .= " AND `type` = '$type'";
	}
	$_CACHE["list_{$type}"] = array();
	$sql = "SELECT $field FROM ".tname('post')." WHERE 1 {$wheresql} AND `status` = '1' ORDER BY dateline DESC";
	if ( $num ) {
		$sql .= " LIMIT $offset, $num";
	}
	$query = $db->query($sql);
	$result = $qmids = array();
	while ( $row = $db->fetch_array($query) )  {
		if ( $row['metas'] ) $qmids[] = $row['id'];
		$result[$row['id']] = $row; 
	}
	$db->free_result($query);
	if ( $qmids ) {
		$query = $db->query("SELECT postid, `var`, `value` FROM ".tname('postmeta')." WHERE postid IN (".simplode($qmids).")");
		while ( $row = $db->fetch_array($query) ) {
			$result[$row['postid']][$row['var']] = $row['value'];
		}
	}
	foreach ( $result as $postid => $row ) {
		$_CACHE['post'][$postid] = $row;
		$_CACHE["list_{$type}"][] = $postid;
	}
	set_loop($type);
}

/**
 * 设定要循环的类型，根据类型循环 $_CACHE['list_类型'] 的数据
 * 
 * @param string $type 类型名，值应与post表type字段对应
 */
function set_loop($type) {
	$_ENV['cur_loop'] = $type;
}

/**
 * 是否有数据或是否循环到末尾
 * 
 * @return 返回true OR false
*/
function have_post() {
	global $_CACHE;
	return !empty($_CACHE['list_'.$_ENV['cur_loop']]);
}

/**
 * 返回循环的数组的当前单元，并存放到$_ENV['post']中，用于进一步处理
 * 如果需要原始数据，可在循环中加一个变量用来接收返回值。
 * 否则建议使用 get_post_field() 提取某个字段的内容。
 *
 * @return 返回$_ENV['post']，循环结束则返回 false
 */
function fetch_post() {
	global $_CACHE;
	$post_id = current($_CACHE['list_'.$_ENV['cur_loop']]);
	next($_CACHE['list_'.$_ENV['cur_loop']]);
	if ( !$post_id ) return false;
	$_ENV['post'] = $_CACHE['post'][$post_id];
	return $_ENV['post'];
}

/**
 * 提取 $_ENV['post'] 的某个字段，返回过滤器处理过的值。
 * 
 * @param string $key    键名
 * @param bool   $return 是否返回值，为true是返回，false直接输出
 */
function post($key = NULL, $return = false) {
	global $_CACHE;
	if ( is_null($key) ) {
		return isset($_ENV['post']);
	}
	switch ($key) {
		case 'url' :
			$value = url('mod=post&id='.$_ENV['post']['id'].'&alias='.$_ENV['post']['alias']); break;
		case 'posttime' :
			$value = get_date($_ENV['post']['dateline']); break;
		case 'category' :
			$cate = $_CACHE['cate'][$_ENV['post']['cateid']];
			$value = sprintf('<a href="%s" title="%s">%s</a>', url('?mod=cate&id='.$cate['id'].'&alias='.$cate['alias']), $cate['catename'], $cate['catename']);
			break;
		case 'title' :
		case 'excerpt' :
		case 'content' :
			global $_USER;
			$value = $_ENV['post'][$key];
			if ( !empty($_ENV['post']['password']) && $_USER['id'] != $_ENV['post']['userid'] ) {
				$password = get_cookie('protected_post_'.$_ENV['post']['id']);
				if ( $password != $_ENV['post']['password'] ) {
					if ( $key == 'title' ) {
						$value = __('加密文章');
					} else {
					$value = '<div id="protected_post_'.$_ENV['post']['id'].'">
					<form method="post" action="javascript:protected_post('.$_ENV['post']['id'].', \''.$key.'\');">
					<div class="protected_post"><h4>'.__('加密文章').'</h4><p>'.__('这篇日志已被密码保护，请输入密码后查看。').'<br />
					'.__('密码').': <input type="password" name="password'.$_ENV['post']['id'].'" size="15" /> 
					<input type="submit" name="submit'.$_ENV['post']['id'].'" value="'.__('提交').'" /></p></div>
					</form></div>';
					}
				}
			}
			break;
		default :
			$value = $_ENV['post'][$key];
	}
	if ( $return ) {
		return apply_filter("post_{$key}", $value);
	} else {
		echo apply_filter("post_{$key}", $value);
	}
}
?>